﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ADDDF.Infrastructure.Collections;

namespace ADDDF.Infrastructure.MemoryBound
{
    public static class MBDataStore
    {
        class RecordBase
        {
            public string Name { get; set; }
        }

        class EntitySetRecord : RecordBase
        {
            public IEntityValueSet<IEntity> EntitySet { get; set; }
        }

        class IntKeyRecord : RecordBase
        {
            public int NextKey { get; set; }
        }

        private static Dictionary<string, EntitySetRecord> _entitySets;
        private static Dictionary<string, IntKeyRecord> _intKeys;
        
        static MBDataStore()
        {
            _entitySets = new Dictionary<string, EntitySetRecord>();
            _intKeys = new Dictionary<string, IntKeyRecord>();
        }

        public static void Reset()
        {
            lock (_intKeys)
            {
                _intKeys.Clear();
            }
            lock (_entitySets)
            {
                _entitySets.Clear();
            }
        }

        #region EntitySet Access Methods

        public static bool HasEntitySet(string name)
        {
            return _entitySets.ContainsKey(name);
        }

        public static IEntityValueSet<IEntity> GetEntitySet(string name)
        {
            return _entitySets[name].EntitySet;
        }

        public static IEntityValueSet<IEntity> AddEntitySet(string name,
            IEnumerable<IEntity> defaultData,
            Func<IEntity, IEntity> cloneFunc)
        {
            lock (_entitySets)
            {           
                if (HasEntitySet(name))
                    throw new InvalidOperationException("EntitySet '" + name + "' already exists");

                EntityValueSet<IEntity> evs = new EntityValueSet<IEntity>(defaultData, cloneFunc);

                _entitySets.Add(name, new EntitySetRecord { Name = name, EntitySet = evs });
            }

            return _entitySets[name].EntitySet;
        }

        #endregion

        #region Integer Key Generation Methods

        /// <summary>
        /// Get next unique integer key.
        /// </summary>
        /// <param name="name">Name of the collection</param>
        /// <returns></returns>
        public static int GetNextIntKey(string name)
        {
            lock (_intKeys)
            {
                if(!_intKeys.ContainsKey(name))
                    _intKeys.Add(name, new IntKeyRecord { Name = name, NextKey = 1 });

                int nextKey = _intKeys[name].NextKey;

                _intKeys[name].NextKey = nextKey + 1;

                return nextKey;
            }
        }

        /// <summary>
        /// Sets next integer key.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="value"></param>
        public static void SetNextIntKey(string name, int value)
        {
            lock (_intKeys)
            {
                if (!_intKeys.ContainsKey(name))
                    _intKeys.Add(name, new IntKeyRecord { Name = name, NextKey = value });
                else
                    _intKeys[name].NextKey = value;
            }
        }

        #endregion      
  
        // For locking the whole MBDataSource
        public static object ForLock = typeof(MBDataStore);
    }
}
